#include<iostream>
#include<cstdlib>
#include<queue>
#include<unistd.h>
#include<pthread.h>

#define MAX_QUEUE 5
template <class T>
class BlockQueue{
  private: 
    int _capacity;
    std::queue<T> _queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_pro;//生产者条件变量
    pthread_cond_t _cond_con;//消费者条件变量
  public:
    BlockQueue(int cap = MAX_QUEUE )//构造函数
      :_capacity(cap){
      pthread_mutex_init(&_mutex,NULL);
      pthread_cond_init(&_cond_con,NULL);
      pthread_cond_init(&_cond_pro,NULL);
    }

    ~BlockQueue(){
      pthread_mutex_destroy(&_mutex);//销毁互斥锁
      pthread_cond_destroy(&_cond_con);//销毁条件变量
      pthread_cond_destroy(&_cond_pro);//销毁条件变量
    }

    bool Push(const T &data){   //入队列
      pthread_mutex_lock(&_mutex);//先加锁
      while(_queue.size() == _capacity ){   //循环判断队列是否还有空间
        pthread_cond_wait(&_cond_pro,&_mutex);//阻塞生产者
      }
      _queue.push(data);
      pthread_mutex_unlock(&_mutex);
      pthread_cond_signal(&_cond_con);//唤醒消费者
    }
    
    bool Pop(T* data){
      pthread_mutex_lock(&_mutex);
      while(_queue.empty() == true){ //循环判断队列是否为空
        pthread_cond_wait(&_cond_con,&_mutex);
      }
      *data = _queue.front();//获取队头元素
      _queue.pop();
      pthread_mutex_unlock(&_mutex);
      pthread_cond_signal(&_cond_pro);//唤醒生产者
    }
};

void* consumer(void* arg){
  BlockQueue<int> *p = (BlockQueue<int>*)arg;
  while(1){
    int data;
    p->Pop(&data);
    printf("consumer get data: %d-----\n",data);
  }
  return NULL;
}

void* producer(void* arg){
  BlockQueue<int> *p =(BlockQueue<int>*)arg;
  int data = 0;
  while(1){
    p->Push(data);
    printf("producer put data: %d+++++\n",data++);//入队列的数字每次加1
  }
  return NULL;
}

int main()
{
  int ret;
  pthread_t ctid[4],ptid[4];

  BlockQueue<int> q;
  for(int i = 0; i < 4; ++i)
  {
    ret = pthread_create(&ctid[i],NULL,consumer,(void*)&q);
    if(ret != 0){
      std::cout<<"pthread create error"<<std::endl;
    }
    
    ret = pthread_create(&ptid[i],NULL,producer,(void*)&q);
    if(ret != 0){
      std::cout<<"pthread create error"<<std::endl;
    }
  }

  for(int i = 0; i<4; ++i)//等待线程退出
  {
    pthread_join(ctid[i],NULL);
    pthread_join(ptid[i],NULL);
  }
  return 0;
}
